package com.huilian.iotbox.admin.security;


import com.huilian.iotbox.admin.service.UserService;
import com.huilian.iotbox.data.common.RedisKey;
import com.huilian.iotbox.data.common.RedisLockKey;
import com.huilian.iotbox.data.enums.PermissionPlatformTypeEnum;
import com.huilian.iotbox.data.enums.RoleEnum;
import com.huilian.iotbox.data.po.Permission;
import com.huilian.iotbox.data.service.PermissionCommonService;
import com.huilian.iotbox.data.vo.UserInfo;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.Serializable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;


/**
 * @author: 少凡
 * @Date 2018/1/25
 */
@Slf4j
@Component("rbacService")
public class RbacServiceImpl implements RbacService {

    private AntPathMatcher antPathMatcher = new AntPathMatcher();

    @Autowired
    private RedissonClient redissonClient;
    @Autowired
    private PermissionCommonService permissionCommonService;
    @Autowired
    private UserService userService;
    @Resource
    private RedisTemplate<String, Serializable> redisCacheTemplate;

    @Override
    public boolean hasPermission(HttpServletRequest request, Authentication authentication) {
        final String userId = (String) authentication.getPrincipal();
        final Integer permissionPlatformType = PermissionPlatformTypeEnum.PC_WEB_PAGE.getCode();
        final String pcPermissionLockKey = String.format(RedisLockKey.PERMISSION_LOCK, permissionPlatformType, userId);
        RLock lock = redissonClient.getLock(pcPermissionLockKey);
        UserInfo userInfo = userService.getLoginUserInfo(request);
        try {
            final boolean tryLock = lock.tryLock(10, TimeUnit.SECONDS);
            if (tryLock) {
                log.info("hasPermission-获取到锁");

                String method = request.getMethod();
                boolean hasPermission = false;

                //读取用户所拥有权限的所有URL
                final String key = String.format(RedisKey.PERMISSION_USERID_V2, permissionPlatformType, userId);
//                List<Permission> urls = null;
                List<Permission> urls = (List<Permission>) redisCacheTemplate.opsForValue().get(key);
                if (StringUtils.isEmpty(urls) || urls.size() == 0) {
                    //判断userId是主账号还是子账号
                    if(userInfo.getRoleId().equals(RoleEnum.SUB_ACCOUNT.getRoleId())){
                        //子账号
                        urls = permissionCommonService.findUserPermissionV2(Integer.parseInt(userId), permissionPlatformType);
                    }else {
                        //主账号
                        urls = permissionCommonService.findUserPermission(Integer.parseInt(userId), permissionPlatformType);
                    }
//                    urls = permissionCommonService.findUserPermission(Integer.parseInt(userId), permissionPlatformType);
                    redisCacheTemplate.opsForValue().set(key, (Serializable) urls, 30, TimeUnit.MINUTES);
                }

                for (Permission permission : urls) {
                    if (antPathMatcher.match(permission.getUrl(), request.getRequestURI())) {
                        System.out.println("permission.getUrl()" + permission.getUrl());
                    }
                    if (antPathMatcher.match(permission.getUrl(), request.getRequestURI()) && method.equals(permission.getMethod())) {
                        hasPermission = true;
                        break;
                    }
                }
                if (!hasPermission) {
                    // 权限校验不通过，进入查看是否为免授权

                    // 先查出当前平台所有免权限的权限
                    final List<Permission> noAuthPermissionList = permissionCommonService.findAllNoAuthPermissionByPlatformType(permissionPlatformType);
                    Map<String, Permission> noAuthPermissionMap = new HashMap<>();
                    if (!org.springframework.util.StringUtils.isEmpty(noAuthPermissionList) && noAuthPermissionList.size() > 0) {
                        noAuthPermissionMap = noAuthPermissionList.stream().collect(Collectors.toMap(Permission::getUrl, a -> a, (k1, k2) -> k1));
                    }

                    if (!org.springframework.util.StringUtils.isEmpty(noAuthPermissionMap.get(request.getRequestURI()))) {
                        hasPermission = true;
                    }
                }
                return hasPermission;
            } else {
                log.warn("hasPermission-未获取到锁");
                return false;
            }
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        } finally {
            if (!StringUtils.isEmpty(lock) && lock.isHeldByCurrentThread()) {
                lock.unlock();
                log.info("hasPermission-解锁成功");
            } else {
                log.error("hasPermission-lock is null or lock isNotHeldByCurrentThread");
            }
        }
    }
}
